using System;
using System.Collections.Generic;
using System.Runtime.Hosting;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor.Drawers;
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
using XYTerrain.Runtime;
using Debug = UnityEngine.Debug;

namespace XYTerrain.Editor

{
    // 该窗口去读取一个配置好的场景信息内容 进行地形图片读取，以及根据选中进行地形加载。

    // 该窗口第一个功能是用于做Terrain 缩略图的生成 并根据SceneManager名的数量进行分割排序
    public class EditorSceneLoader :EditorWindow 
    {

        public static EditorSceneData sceneData;
        public string[] toolbarStrings = { "场景加载", "地形预览生成" };
        public int toolbarInt
        {
            get => m_toolbarInt;
            set
            {
                if (m_toolbarInt != value)
                {
                    dirty = true;
                    m_toolbarInt = value;
                }
            }
        }
        
        public List<SceneCollectionManager> removeList = new List<SceneCollectionManager>();
        public Color backGroundColor;

        public System.Action<Scene[]> LoadSceneAct ;
        public System.Action<Scene[]> UnLoadSceneAct;
        
        // ------- 地形加载用数据 ------------
        public EditorLoaderDataMessage loaderData;
        public bool[] sceneLoadBool { get => loaderData.sceneLoadBool; }
        Dictionary<string, List<UnityEngine.SceneManagement.Scene>> loadedScene { get => loaderData.loadedScene; }
        //-------------------------------------


        private bool assignGlobalScene
        {
            get => sceneData.useAssignScene;
            set
            {
                if (sceneData.useAssignScene != value)
                {
                    sceneData.useAssignScene = value;
                }
                else
                {
                    //DoNoting 
                }
                
            }
        }

        private bool dirty = false;
        public int m_toolbarInt = 0;
        



        [MenuItem("Tools/Nature Manufacture/XY/SceneLoader")]
        public static void Init()
        {

            EditorSceneLoader window = EditorWindow.GetWindow<EditorSceneLoader>("SceneLoader");
            window.centerHelpBox =  new GUIStyle(EditorStyles.helpBox)
            {
               alignment = TextAnchor.MiddleCenter,
               fontSize = 8,
               fontStyle = FontStyle.Normal,
            };

            window.Show();
            window.minSize = new Vector2(300, 550);
        }

        /// <summary>
        ///  通过其他途径打开 EditorWindow 并添加回调到 加载，卸载中
        /// </summary>
        /// <param name="onLoad"> 在加载场景后的回调</param>
        /// <param name="onUnLoad">在卸载场景后的回调</param>
        /// <returns></returns>
        public static EditorSceneLoader EnableOnEditor(Action<Scene[]> onLoad=null,Action<Scene[]> onUnLoad=null)
        {
            EditorSceneLoader window = EditorWindow.GetWindow<EditorSceneLoader>("SceneLoader");
            window.LoadSceneAct += onLoad;
            window.UnLoadSceneAct += onUnLoad; 
            window.centerHelpBox =  new GUIStyle(EditorStyles.helpBox)
            {
               alignment = TextAnchor.MiddleCenter,
               fontSize = 8,
               fontStyle = FontStyle.Normal,
            };
            window.Show();
            return window;
        }


        private void LoadSceneData()
        {
      
            if(Application.isPlaying) return;
            if (sceneData == null)
            {

                var objPath = AssetDatabase.FindAssets("t:EditorSceneData");
                if (objPath != null&& objPath.Length>0)
                {
                    sceneData = AssetDatabase.LoadAssetAtPath<EditorSceneData>(AssetDatabase.GUIDToAssetPath(objPath[0]));
                    Debug.Log("加载编辑器场景数据完成");
                    if (objPath.Length > 1)
                    {
                        Debug.LogWarning("工程中应该只保留一份sceneData");
                    }
                }
            }
        }

        public void Awake()
        {
            LoadSceneData();
        }

        public void OnEnable(){

            LoadSceneData();
        }



        void OnGUI()
        {




            sceneData = (EditorSceneData)EditorGUILayout.ObjectField(sceneData, typeof(XYTerrain.Runtime.EditorSceneData), true);
            if (sceneData == null) return;
            DrawFuctionTag();
            if (Application.isPlaying)
            {
                EditorGUILayout.HelpBox("运行状态中无法使用",MessageType.Warning);    
                return;
            }
            
            switch (toolbarInt)
            {
                case 0:

                    if (SceneManager.GetActiveScene().name != EditorSceneData.EditorSceneName)
                    {
                       EditorGUILayout.HelpBox("当前场景不是EditorScene",MessageType.Warning);
                       if (GUILayout.Button("加载Editor场景"))
                       {
                        var scenePath =    AssetDatabase.FindAssets($"{EditorSceneData.EditorSceneName} t:scene");
                        if (scenePath.Length > 0)
                        {
                            // var editorScene = AssetDatabase.LoadAssetAtPath<SceneAsset>(AssetDatabase.GUIDToAssetPath(scenePath[0]));
                            var path = AssetDatabase.GUIDToAssetPath(scenePath[0]);
                            EditorSceneManager.OpenScene(path);
                        }
                           // EditorSceneManager.OpenScene() 
                       }
                       return; 
                    }
                    if (loaderData == null) InitLoaderData();
                    CheckDirty();
                    DrawMapGroup();
                    break;
                case 1:
                    DrawSceneData();
                    BeakPreviewTex();
                    DrawSceneSetting();
                    break;
                // default:
                //     DrawSceneData();
                //     break;
            }
        }
        void DrawFuctionTag()
        {
            toolbarInt = GUILayout.Toolbar(toolbarInt, toolbarStrings);
        }

        void CheckDirty()
        {
            
            
            if (dirty)
            {
                if (loaderData.sceneLoadBool==null || loaderData.sceneLoadBool.Length != sceneData.splitTime * sceneData.splitTime)
                {
                    loaderData.sceneLoadBool = new bool[sceneData.splitTime * sceneData.splitTime];
                }
                

                if (loaderData.layerSelecter==null ||loaderData.layerSelecter.Length!=sceneData.collectionManagers.Count)
                {
                    loaderData.layerSelecter = new bool[sceneData.collectionManagers.Count];
                }
            }
            dirty = false;
        }

        void InitLoaderData()
        {
            if (sceneData.globalScenePath!=null&&SceneManager.GetActiveScene().name == sceneData.globalSceneName)
            {
                Debug.Log("InGlobalScene");
                return;
            }

            if (SceneManager.GetActiveScene().name != EditorSceneData.EditorSceneName) return;
            
            loaderData = FindObjectOfType(typeof(EditorLoaderDataMessage)) as EditorLoaderDataMessage;
            if (loaderData == null)
            {
                GameObject gameObject = new GameObject("_EditorLoaderDataMessage");
                loaderData = gameObject.AddComponent<EditorLoaderDataMessage>();
                loaderData.sceneLoadBool = new bool[sceneData.splitTime * sceneData.splitTime];
                Debug.Log(sceneData.splitTime);
                // gameObject.hideFlags = HideFlags.HideInHierarchy | HideFlags.DontSaveInBuild;
                gameObject.hideFlags = HideFlags.DontSaveInBuild;
                gameObject.tag = "EditorOnly";
                loaderData.sceneLoadBool = new bool[0];
                loaderData.layerSelecter = new bool[0];
                Undo.RegisterCreatedObjectUndo(gameObject, "Create object");
                Debug.Log("生成场景保存数据");

            }else
            {
                List<int> activeSubScene = new List<int>();

                if (loaderData.sceneLoadBool==null || loaderData.sceneLoadBool.Length != sceneData.splitTime * sceneData.splitTime)
                {
                    loaderData.sceneLoadBool = new bool[sceneData.splitTime * sceneData.splitTime];
                }
                

                if (loaderData.layerSelecter==null ||loaderData.layerSelecter.Length!=sceneData.collectionManagers.Count)
                {
                    loaderData.layerSelecter = new bool[sceneData.collectionManagers.Count];
                }
                 
                 
                for (int i = 0; i < loaderData.sceneLoadBool.Length; i++)
                {
                    if (loaderData.sceneLoadBool[i])
                    {
                        activeSubScene.Add(i);
                        Vector2Int vec = IndexToSceneID(i);
                        // Debug.Log( "x :"+vec.x  + "y:"+vec.y);
                        LoadScene(vec.x, vec.y);
                    }
                }
            }


            if (sceneData != null)
            {
               LoadGlobalScene();
            }
            
            

        }


        /// <summary>
        /// 场景指定配置
        /// </summary>
        void DrawSceneSetting()
        {

            EditorGUILayout.Space(10);
            assignGlobalScene = EditorGUILayout.Toggle("指定全局场景", assignGlobalScene);

            
            EditorGUILayout.BeginVertical(EditorStyles.helpBox); 
            if (assignGlobalScene)
            {
                
                EditorGUI.BeginChangeCheck();
                sceneData.globalScene = EditorGUILayout .ObjectField("场景",sceneData.globalScene,typeof(SceneAsset),true) as SceneAsset;
                if (EditorGUI.EndChangeCheck())
                {
                    if (sceneData.globalScene != null)
                    {
                        sceneData.assignSceneName = sceneData.globalScene.name;
                        sceneData.assignScenePath =  AssetDatabase.GetAssetPath(sceneData.globalScene);    
                    }
                    
                }
                EditorGUILayout.LabelField("指定场景名称 :"+ sceneData.assignSceneName,EditorStyles.helpBox); 
                EditorGUILayout .LabelField("指定场景路径 :"+ sceneData.assignScenePath,EditorStyles.helpBox);
                
            }
            else
            {
                EditorGUILayout.LabelField("默认场景名称 :"+ sceneData.defaultGlobalSceneName,EditorStyles.helpBox);
                EditorGUILayout.LabelField("默认场景路径 :" + sceneData.defaultGlobalScenePath, EditorStyles.helpBox);
            }
            EditorGUILayout.EndVertical(); 
                
        }
        
        void DrawSceneData()
        {

            EditorGUILayout.LabelField("场景集合器");


            EditorGUILayout.BeginVertical(EditorStyles.helpBox);

            EditorGUI.BeginChangeCheck();
            for (int i = 0; i < sceneData.collectionManagers.Count; i++)
            {
                EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);

                sceneData.collectionManagers[i] = (SceneCollectionManager)EditorGUILayout.ObjectField(sceneData.collectionManagers[i], typeof(SceneCollectionManager), true);
                DrawRemoveBtn(i);

                EditorGUILayout.EndHorizontal();
            }

            if (EditorGUI.EndChangeCheck())
            {
                foreach (var i in removeList) sceneData.collectionManagers.Remove(i);
                removeList.Clear();
                // if(loaderData!=null) loaderData.SetLayerSelecter(sceneData.collectionManagers.Count);
            }

            if (GUILayout.Button("+"))
            {
                sceneData.collectionManagers.Add(null);
                // if(loaderData!=null) loaderData.SetLayerSelecter(sceneData.collectionManagers.Count);
            }

            EditorGUILayout.EndVertical();


        }

        void DrawRemoveBtn(int index)
        {
            if (GUILayout.Button("X")) { removeList.Add(sceneData.collectionManagers[index]); }
        }

        void BeakPreviewTex()
        {

            var o = Selection.activeGameObject;
            if (o == null)
            {
                EditorGUILayout.HelpBox("选中目标地形以生成预览图", MessageType.Info);
            }
            else
            {

                if (GUILayout.Button("生成"))
                {
                    var terrain = o.GetComponent<Terrain>();
                    if (terrain == null)
                    {
                        Debug.LogError("未选择地形");
                        return;
                    }
                    string path = EditorUtility.OpenFolderPanel(" 保存位置", Application.dataPath, null);
                    if (string.IsNullOrEmpty(path)) return;
                    var rt = TerrainPreviewBaker.GetTerrainPreviewTex(terrain, terrain.name);
                    int splitTime = (int)Mathf.Sqrt(sceneData.collectionManagers[0].names.Length);
                    Debug.Log(sceneData.collectionManagers[0].names.Length);
                    sceneData.splitTime = splitTime;
                    var texs = TerrainPreviewBaker.SplitTerrainPreviewTex(rt, splitTime, path);

                    sceneData.splitTextures.Clear();
                    sceneData.splitTexturesPath.Clear();
                    sceneData.boundSize = terrain.terrainData.size / splitTime;
                    for(int i = 0 ; i<texs.Length;i++ ){
                        sceneData.splitTexturesPath.Add(texs[i]);
                    }


                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();

                    LoadBeakSplitTex();

                    
                    if(loaderData!=null){
                        loaderData.sceneLoadBool = new bool[sceneData.splitTime * sceneData.splitTime];
                        loaderData.layerSelecter = new bool[sceneData.collectionManagers.Count];
                    }

                    EditorUtility.SetDirty(sceneData);
                    AssetDatabase.SaveAssets();
                    // AssetDatabase.SaveAssetIfDirty(sceneData);
                    Debug.Log("生成完毕 保存路径：" + path);
                }
            }

        }

        void LoadBeakSplitTex()
        {


            sceneData.splitTextures = new List<Texture2D>();

            for (int i = 0; i < sceneData.splitTexturesPath.Count; i++)
            {

                var tex = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets" + sceneData.splitTexturesPath[i]);
                sceneData.splitTextures.Add(tex);

            }

        }


        private GUIStyle centerHelpBox; 
        
        #region   场景加载相关


        void DrawMapGroup()
        {


            if (sceneData.splitTextures.Count == 0 || sceneData.splitTexturesPath.Count == 0)
            {
                EditorGUILayout.HelpBox("先进行场景信息配置", MessageType.Warning);
                    return;
            }

            EditorGUILayout.Space(10);
            GUILayout.Label("场景层选择器");




            EditorGUILayout.BeginVertical(EditorStyles.helpBox);

            for (int i = 0; i < loaderData.layerSelecter.Length; i++)
            {
                loaderData.layerSelecter[i] = EditorGUILayout.Toggle(sceneData.collectionManagers[i].prefixName, loaderData.layerSelecter[i]);
            }

            EditorGUILayout.EndVertical();



            GUILayout.Label("场景加载选择器");

            EditorGUILayout.BeginHorizontal();

            for (int x = 0; x < sceneData.splitTime; x++)
            {
                EditorGUILayout.LabelField((x).ToString(),EditorStyles.centeredGreyMiniLabel,GUILayout.Width(32),GUILayout.Height(32),GUILayout.ExpandWidth(false));
            }
            
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.BeginVertical(EditorStyles.helpBox,GUILayout.Width(sceneData.splitTime*32));
            EditorGUILayout.Space (10);
            for (int z = sceneData.splitTime - 1; z >= 0; z--)
            {

                EditorGUILayout.BeginHorizontal();
                for (int x = 0; x < sceneData.splitTime; x++)
                {

                    int index = x * sceneData.splitTime + z;
                    if(sceneLoadBool[index]){
                            backGroundColor = GUI.backgroundColor;
                            GUI.backgroundColor = Color.green;
                    }
                    
                    if (GUILayout.Button(new GUIContent(){image = sceneData.splitTextures[index],tooltip = $"ID:X{x}_Z{z}"} , GUILayout.Width(32), GUILayout.Height(32)))
                    {
                        SceneActive(x, z);
                    }
                    if(sceneLoadBool[index]){
                        GUI.backgroundColor = backGroundColor;
                    }

                }
                
                EditorGUILayout.EndHorizontal();
            }
            EditorGUILayout.Space (10);
            EditorGUILayout.EndVertical();


            EditorGUILayout.BeginVertical();
            EditorGUILayout.Space(10);
            for (int z = sceneData.splitTime - 1; z >= 0; z--)
                EditorGUILayout.LabelField((z).ToString(),EditorStyles.centeredGreyMiniLabel,GUILayout.Width(32),GUILayout.Height(32),GUILayout.ExpandWidth(false));
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.EndHorizontal(); 
            
            

            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            
            
            SceneController(); 
            EditorGUILayout.EndVertical();
            
            


        }

        

        void SceneController()
        {
            // EditorSceneManager.    

            if (GUILayout.Button("移除所有场景"))
            {

                Debug.Log("移除？");
                int count = SceneManager.sceneCount;
                int beginIndex = 1;




                List<Scene> loadedScene = new List<Scene>();


                for (int i = 1; i < count; i++)
                {
                    var scene = SceneManager.GetSceneAt(i);
                    if(scene.name==sceneData.globalSceneName) continue;
                    loadedScene.Add(scene);
                }
                
                
                for (int i = 0; i < loadedScene.Count; i++)
                {
                    if (loadedScene[i].isLoaded)
                    {
                        EditorUtility.DisplayProgressBar( "关闭全部场景", $"正在关闭第{i}/{count}个场景" , (float)i / count);
                        EditorSceneManager.CloseScene(loadedScene[i],true);    
                        EditorApplication.Step();
                    }
                }
                loadedScene.Clear();

                for (int i = 0; i < loaderData.sceneLoadBool.Length; i++)
                {
                    loaderData.sceneLoadBool[i] = false;
                }
                
                //问题就出在这个地方了，场景卸载过程中没有办法完全进行卸载 Destory命令保留到了PlayMode中 :w
                EditorUtility.SetDirty(loaderData);
                EditorUtility.ClearProgressBar();
                
            }

            
           // EditorSceneManager.RestoreSceneManagerSetup();

            if (GUILayout.Button("加载所有场景"))
            {
                
                // EditorUtility.
                
                int num = 1;
                for (int z = sceneData.splitTime - 1; z >= 0; z--)
                {
                    for (int x = 0; x < sceneData.splitTime; x++)
                    {
                        int index = x * sceneData.splitTime + z;
                        if (sceneLoadBool[index])
                        {
                            num += 1;
                            continue;
                        }
                        sceneLoadBool[index] = true;
                        EditorUtility.DisplayProgressBar( "加载全部场景", $"正在加载第{num}/{sceneData.splitTextures.Count}个场景" , (float)num / sceneData.splitTextures.Count);
                        LoadScene(x,z);
                        num += 1;
                    }
                }
                // EditorUtility.SetDirty(loaderData);
                EditorUtility.ClearProgressBar();
                
            }
        }
        
        
        

        void SceneActive(int x, int z)
        {
            int index = x * sceneData.splitTime + z;
            sceneLoadBool[index] = !sceneLoadBool[index];
            EditorUtility.SetDirty(loaderData);
            if (sceneLoadBool[index])
            {
                LoadScene(x, z);
            }else
            {
                UnLoadScene(x, z);
            }

        }

        void LoadScene(int x, int z)
        {

            if (Application.isPlaying) return; 
                
            
            string name = $"_x{x}_z{z}";

            if (!loadedScene.ContainsKey(name))
            {
                loadedScene.Add(name, new List<UnityEngine.SceneManagement.Scene>());
            }

            for(int i = 0 ; i<sceneData.collectionManagers.Count;i++){
                var layerMsg = sceneData.collectionManagers[i];
                if (loaderData.layerSelecter[i]) loadedScene[name].Add(EditorSceneManager.OpenScene(layerMsg.path + layerMsg.prefixScene + name + ".unity", OpenSceneMode.Additive));
                LoadSceneAct?.Invoke(loadedScene[name].ToArray());
            }
            

            
            // EditorSceneManager.OpenScene();
        }


        void UnLoadScene(int x, int z)
        {
            if (Application.isPlaying) return; 
            if (loadedScene.ContainsKey($"_x{x}_z{z}")){
                var list = loadedScene[$"_x{x}_z{z}"];
                foreach (var i in list)
                {
                    EditorSceneManager.CloseScene(i, true);
                }
                var sceneArray = list.ToArray();
                UnLoadSceneAct?.Invoke(sceneArray);
            }
        }


        /// <summary>
        ///  根据当前情况判断是否需要生成全局信息。
        /// </summary>
        void InitGlobalScene()
        {
            var path  =  AssetDatabase.GetAssetPath(sceneData);
           path = System.IO.Directory.GetParent(path)?.ToString();
           
           // TODO
           AssetDatabase.CreateFolder(path,sceneData.globalSceneName);
           
           var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);
           path += sceneData.globalScenePath; 
           
           EditorSceneManager.SaveScene(scene,path);
           EditorSceneManager.CloseScene(scene,true);
           AssetDatabase.SaveAssets();
           AssetDatabase.Refresh();
        }
        
        /// <summary>
        ///  GlobalScene用于保存全局设置信息，如光照，后处理，场景处理效果 ,如果工程中存在一个用于存储这些GamePlay的场景 也可以用工程场景代替。
        /// </summary>
        void LoadGlobalScene()
        {


            if (Application.isPlaying) return;
            if (SceneManager.GetActiveScene().name != EditorSceneData.EditorSceneName) return;

            if (sceneData.useAssignScene)
            {
                EditorSceneManager.OpenScene(sceneData.assignScenePath, OpenSceneMode.Additive);
            }
            else
            {
                // globasScene 生成在ScendData同个根目录文件夹下
                var path = AssetDatabase.GetAssetPath(sceneData);
                path = System.IO.Directory.GetParent(path)?.ToString();
                path += sceneData.globalScenePath;

                var longPath = Application.dataPath.Substring(0, Application.dataPath.Length - 6)+path;

                if (!System.IO.File.Exists(longPath))
                {
                    Debug.Log("不存在GlobalScene 创建GlobalScene");    
                    InitGlobalScene(); 
                }  
             
                EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);    
            }
             
            
             
        }

        /// <summary>
        ///  获取当前场景所有场景
        /// </summary>
        /// <returns></returns>
        public  Scene[] GetCurrentAllScene()
        {
            List<Scene> sceneList = new List<Scene>();
            int count = SceneManager.sceneCount;
            for (int i  = 1;  i  < count;  i ++)
            {
                var scene =  SceneManager.GetSceneAt(i);
                if(scene.name!=sceneData.globalSceneName) sceneList.Add(scene);
            }

            return sceneList.ToArray();

        }
        
        /// <summary>
        ///  获取当前场景中所有场景ID:
        /// </summary>
        /// <returns></returns>
        public List<Vector2Int> GetCurrentSceneID()
        {
            List<Vector2Int> idList = new List<Vector2Int>();
            for (int i = 0; i < loaderData.sceneLoadBool.Length; i++)
            {
                if(loaderData.sceneLoadBool[i]) idList.Add(IndexToSceneID(i));
            }
            return idList;
        }

        private Vector2Int IndexToSceneID(int id)
        {
            int x = Mathf.FloorToInt( ((float)id / sceneData.splitTime));
            int z = ((id) %(sceneData.splitTime));
            return new Vector2Int(x, z);
        }
        
        


        #endregion
    }
}

